package mobile.game.core.support;

import java.util.HashMap;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Queue;

import mobile.game.core.Port;
import mobile.game.core.support.function.JowFunction2;

/**
 * @author g
 *
 * timer队列
 */
public class TimerQueue {
	/** id 分配*/
	private long idAlloc = 0;
	
	/** timer队列*/
	private Queue<Timer> timers = new PriorityQueue<>();
	
	/** timerid -> timer*/
	private Map<Long, Timer> id2Timer = new HashMap<>();
	
	public long createTimer(long delay, long period, JowFunction2<Long, Param> pfn, Param param) {
		Timer timer = new Timer(++idAlloc);
		timer.canceled = false;
		
		Port port = Port.getCurrent();
		if(port != null) {
			timer.expiredTime = port.getTimeCurrent() + delay;
		} else {
			timer.expiredTime = System.currentTimeMillis() + delay;
		}
		
		timer.periodTime = period;
		timer.timerProc = pfn;
		timer.param = param;
		
		timers.add(timer);
		id2Timer.put(timer.id, timer);
		
		return timer.id;
	}
	
	public void cancelTimer(long timerId) {
		Timer timer = id2Timer.get(timerId);
		if(timer != null) {
			timer.canceled = true;
		}
	}
	
	public void update(long now) {
		while(!timers.isEmpty()) {
			Timer timer = timers.peek();
			if(now < timer.expiredTime) {
				break;
			}
			
			timers.poll();
			
			if(!timer.canceled) {
				timer.execute();
				
				if(timer.periodTime > 0 && !timer.canceled) {
					timer.expiredTime = now + timer.periodTime;
					timers.add(timer);
				} else {
					id2Timer.remove(timer.id);
				}
			} else {
				id2Timer.remove(timer.id);
			}
		}
	}
	
	public void cleanup() {
		timers.clear();
		id2Timer.clear();
	}
}

/**
 * @author g
 *
 * 一个timer
 */
class Timer implements Comparable<Timer> {
	long id;
	boolean canceled = false;
	long expiredTime;
	long periodTime;
	JowFunction2<Long, Param> timerProc = null;
	Param param = null;
	
	Timer(long id) {
		this.id = id;
	}
	
	void execute() {
		if(timerProc != null) {
			timerProc.apply(id, param);
		}
	}

	@Override
	public int compareTo(Timer o) {
		if(expiredTime < o.expiredTime) {
			return -1;
		} else if(expiredTime > o.expiredTime) {
			return 1;
		} else {
			return 0;
		}
	}
}
